package com.zlyx.easy.core.factory;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.BeanNameGenerator;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ResourceLoader;

import com.zlyx.easy.core.app.AppUtils;
import com.zlyx.easy.core.collections.Lists;
import com.zlyx.easy.core.factory.defaults.annotations.FactoryBean;
import com.zlyx.easy.core.factory.interfaces.FactoryBeanDefiner;
import com.zlyx.easy.core.loggers.Logger;
import com.zlyx.easy.core.utils.ClassUtils;
import com.zlyx.easy.core.utils.ObjectUtils;
import com.zlyx.easy.core.utils.StringUtils;

/**
 * <p>
 * 接口式编程配置类
 * </p>
 *
 * @author 赵光
 * @since 2019年1月16日
 */
@Configuration
public class FactoryBeanConfigurer implements BeanDefinitionRegistryPostProcessor, ApplicationContextAware {

	private static List<FactoryBeanDefiner> factoryBeanHandlers = Lists.newList();
	protected String[] basePackages;
	protected Class<? extends Annotation> annotationClass;
	protected ResourceLoader applicationContext;
	protected BeanNameGenerator nameGenerator;
	protected Class<?> markerInterface;

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {

	}

	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
		try {
			Class<?> mainClass = AppUtils.getMainClass();
			initPackages(mainClass);
			if (ObjectUtils.isNotEmpty(factoryBeanHandlers)) {
				ClassPathScanner scanner = new ClassPathScanner(registry);
				scanner.setMarkerInterface(this.markerInterface);
				scanner.setResourceLoader(this.applicationContext);
				FactoryBean factory = null;
				Class<? extends Annotation> scanAnnotation = null;
				for (FactoryBeanDefiner handler : factoryBeanHandlers) {
					factory = handler.getClass().getAnnotation(FactoryBean.class);
					if (factory != null) {
						scanAnnotation = factory.scanAnnotation();
						if (mainClass.getAnnotation(scanAnnotation) == null) {
							scanner.setFactoryBeanHandler(handler.getClass());
							scanner.setAnnotationClass(factory.annotationClass());
							scanner.setBeanNameGenerator(this.nameGenerator);
							scanner.registerFilters();
							scanner.scan(this.basePackages);
						}
					}
				}
			}
		} catch (Exception e) {
			Logger.err(e);
		}
	}

	/**
	 * 初始化项目扫描路径(Spring加载Bean的路径)
	 * 
	 * @param mainClass
	 */
	private void initPackages(Class<?> mainClass) {
		List<String> basePackages = new ArrayList<>();
		boolean flag = true;
		ComponentScan componentScan = mainClass.getAnnotation(ComponentScan.class);
		if (componentScan != null) {
			for (String pkg : componentScan.value()) {
				if (StringUtils.isNotEmpty(pkg)) {
					if (pkg.startsWith("com.zlyx")) {
						flag = false;
					}
					basePackages.add(pkg);
				}
			}
			for (String pkg : componentScan.basePackages()) {
				if (StringUtils.isNotEmpty(pkg)) {
					if (pkg.startsWith("com.zlyx")) {
						flag = false;
					}
					basePackages.add(pkg);
				}
			}
			for (Class<?> clazz : componentScan.basePackageClasses()) {
				basePackages.add(ClassUtils.getPackageName(clazz));
			}
		}
		if (basePackages.isEmpty()) {
			basePackages.add(ClassUtils.getPackageName(mainClass));
		}
		if (flag) {
			basePackages.add("com.zlyx");
		}
		this.basePackages = StringUtils.toStringArray(basePackages);
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) {
		this.applicationContext = applicationContext;
	}

	public static void addFactoryBeanHandler(FactoryBeanDefiner factoryBeanHandler) {
		factoryBeanHandlers.add(factoryBeanHandler);
	}
}
